#include <stdio.h>
#include <stdlib.h>

#include <sys/time.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>

#include "ticket.h"
#include "atomic.h"

#define MAX_BACKOFF 50

int numThreads;
int tid_gen = 0;
pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;


int __thread tid;

int ticket_pause (int delay) {

   int i, j;
   
   for (i = 0; i < delay; i ++) {
      //what do we want the base unit of waiting to be ? 1 nop ? 5 nops ?
      for (j = 0; j < TICKET_TIME_UNIT; j ++) {
         asm __volatile__ ("nop");
      }
   }
   
   return 0;
}


int ticket_mutex_init (ticket_mutex_t *mutex)
{
    mutex->next_ticket = 0;
    mutex->now_serving = 0;
    return 0;
}


int ticket_mutex_lock (ticket_mutex_t *mutex) 
{
    int my_ticket;
    register int counterExp = 2;
    //has to return old value
    my_ticket = fetch_and_increment (& (mutex->next_ticket));
    //register int result = my_ticket - MAX_BACKOFF;
	// register int step_size = (result < 0 ) ? 1 : result % MAX_BACKOFF;
	register int cur;
    
    while ((cur=mutex->now_serving) != my_ticket) {
       //implement backoff here; you can (should) use ticket_pause()
       ticket_pause (counterExp);
       //counterExp = (counterExp >= MAX_BACKOFF) ? MAX_BACKOFF : counterExp << (my_ticket-cur);
	   //counterExp =  counterExp--;

		
		//fastest but not practical
		switch(my_ticket-cur)
		{
			case 1:counterExp=0;
			case 2:counterExp=2;
			case 3:counterExp=20;
			default:counterExp=30;
		}
		
	   //printf("%d\n",counterExp);
    }

    return 0;
}

int ticket_mutex_unlock (ticket_mutex_t *mutex) 
{
   mutex->now_serving = mutex->now_serving + 1;
  
   return 0;
}
